<?php 
/**
* Some utilities (javascript conversion, directory listing, uploading files...).
*<p>This is a static class.</p>
*@package Core
*@author Willy Gardiol <willy@gardiol.org>
*@version 1.0
*/
class CoreUtils extends BaseClassStatic
{
	/**
	* Convert some PHP data to Javascript format.
	*<p>This function is recursive: <b>DO NOT USE WITH RECURSIVE LOOP DATA</b>. Given PHP data (anything
	*but class instances) will be translated to JSON/Javascript data in a suitable format to be sent
	*to the client side without warning for any mis-interpretation. For example, strings containing ' or "
	*are converted to base64 and automatically converted again on the client side. Arrays are converted
	* to javascript objects ({}) and not javascript arrays to avoid extra overhead.</p>
	*@param mixed $data Data to be converted. Anything but objects and handles please.
	*@param bool $use_d64 If true the d64 will be called to convert automatically strings.
	*@return string Javascript formatted data
	*/
	static public function Php2Js($data, $use_d64 = true)
	{
		# WE need to do some parsing to safely send data from PHP to Javascript realms...
		# Arrays needs to be converted to {} sequences 
		if ( is_array( $data ) )
		{
			$ret= "";
			foreach ( $data as $k => $item )
			{
				if ( $ret != "" ) $ret .= ", ";
				# Iterate on array items (warning: will break on recursive-loop arrays)
				$ret .= "\"$k\": ".CoreUtils::Php2Js($item, $use_d64);
			}
			return "{".$ret."}";
		}
		# Booleans are simple
		elseif ( is_bool( $data ) )
			return ( $data ) ? "true" : "false";
		# Numbers and string-literals will become numbers easily...
		elseif ( is_numeric( $data ) )
			return $data;
		# Strings are a bit more complex: when they contains ' or " they will break JS output
		elseif ( is_string( $data ) )
		{	# and we do this by converting them to base64		
			# provide JS with automated decoding, but careful in JSON it is NOT supported!
			if ( $use_d64 )
				return "d64(\"".base64_encode($data)."\")";
			else
				return "\"".base64_encode($data)."\"";
		}
		else
			return "null";
	}
	/**
	* Convert some PHP data to JSON Javascript format.
	*See CoreUtils::Php2Js for more informations. This simply make sure no d64 is used (injvalid JSON).
	*@param mixed $data Data to be converted. Anything but objects and handles please.
	*@return string Valid JSON formatted data
	*/
	static public function Php2Json($data)
	{
		return CoreUtils::Php2Js($data, false );
	}
	/**
	* Reverse the job done by $.param on the client-side word. To read arrays from Javascript to PHP format.
	*@param string $serial_str The string coming from client-side to be converted to PHP format
	*@return mixed The php converted data
	*@todo Make this work with named arrays (ex: multi-input select boxes)
	*/
	static public function JsUnserialize($serial_str)
	{
		#	NOTE: this will NOT work with named arrays!
		#		like multi-input select
		$tmp = array();
		$pairs = explode("&", $serial_str );

		foreach ($pairs as $pair )
		{
			if ( isset( $pair[1] ) )
			{
				list($name, $value) = explode("=", $pair, 2);
				$value = urldecode($value);
				if ( isset( $tmp[$name] ) )
				{
					if ( is_array($tmp[$name]) )
						$tmp[$name][] = $value;
					else
						$tmp[$name] = array( $tmp[$name], $value );
				}
				else
					$tmp[$name] = $value;
			}
		}
		return $tmp;
	}
	/**
	* Return path to the temp folder (usually "site_data/temp").
	*@return string Path to the temporary folder
	*/
	static public function TempFolder()
	{
		if ( !file_exists( "site_data/temp/" ) )
			mkdir( "site_data/temp/" );
		return "site_data/temp/";
	}
	/**
	* Return the path for a unique temporary file. Does not create it.
	*@return string Path to a temporary file (to be created by the caller)
	*/
	static public function TempFile()
	{
		return CoreUtils::TempFolder().uniqid();
	}

	/**
	* List contents of a folder with wildcards, regular expression or file types.
	*<p>List contents of a folder. In its simplest call (no params) will list all the content of a folder.</p>
	*<p>The optional parameters allow for filtering the contents:
	*<ul>
	*<li><b>mask</b>: a PERL regular expression matching the filenames (default is: <i>/.*\/</i> to match all).</li>
	*<li><b>type</b>: can either be <i>f</f> for files and/or <i>d</i> for folder ('df' is the default).</li>
	*<li><b>filter</b>: a callback function to manually filter the result one by one (default: none).</li>
	*</ul>
	*</p><p>The callback has the following prototype: <code>function filter($filename)</code> and should return
	* <i>false</i> if the filename if to be discarded, <i>true</i> otherwise.</p>
	*@param string $path Folder which contents are to be listed
	*@param array $params Flags (see description) in format array( ["mask" => ], ["type" =>], ["filter" => ] )
	*@return array List of matching contents
	*/
	static function ListFolder($path, $params = array())
	{
		$mask = isset($params["mask"]) ? $params["mask"] : "/.*/";
		$type = isset($params["type"]) ? $params["type"] : "df";
		$filter = isset($params["filter"]) && is_callable($params["filter"]) ? $params["filter"] : false;
		$use_filter = $filter !== false;
		$type_d = strpos( $type, "d" ) !== false;
		$type_f = strpos( $type, "f" ) !== false;
		$ret = false;
	
		# Abort if given path is not a folder or if cannot be opened
		if ( is_dir( $path ) && (($dir = opendir($path)) !== false ) )
		{
			# Also exclude from return ".", ".." and ".lastupdate" that are reserved files
			$internal_mask = "/^\.?\.(lastupdate)?$/";
			$ret = array();
			while (($file = readdir($dir)) !== false)
			{
				if ( (preg_match( $mask, $file ) == 1 ) &&
					(preg_match( $internal_mask, $file ) == 0 ) &&
					(
					($type_d && is_dir("$path/$file")) || # is dir if we care
					($type_f && !is_dir("$path/$file"))  # is file if we care
					) &&
					!($use_filter && !$filter($file,$path)) )
					$ret[$file] = $file;
			}
			closedir($dir);
		}
		return $ret;
	}
	/**
	* Retrieve all the data related to a temporary uploaded file, and remove the temporary file.
	*<p>Calling this function will actually load in memory the entire uploaded file and unlink it from disk.</p>
	*<p>The data structure is: array( "type" => type of file, "data" => actual data). </p>
	*@param string $key Identifier for the temporary uploaded file
	*@return array The data structure of the temporary uploaded file.
	*/
	static public function UploadedFileInfo( $key )
	{
		$filename = "site_data/temp_upload/$key";
		if ( file_exists( $filename ) )
		{
			$store = unserialize( file_get_contents( $filename ) );
			if ( $store["session"] == session_id() )
				return $store;
		}
		return false;
	}
	/**
	* Return a temporary uploaded file contents.
	*<p>Note: the tmeporary uploaded file will always be removed after this call.</p>
	*@param string $key Identifier for the temporary uploaded file
	*@return bool The contents of the uploaded file (data structure, see description of <i>UploadedFileInfo</i>)
	*/
	static public function UploadedFileGet( $key )
	{
		$filename = "site_data/temp_upload/$key";
		if ( $store = CoreUtils::UploadedFileInfo($key) )
			unlink( $filename );
		return $store;
	}
	/**
	* Move a temporary uploaded file to a permanent destination.
	*<p>Note: the tmeporary uploaded file will be removed anyway after this call, even if the move is
	*unsuccessful</p>
	*@param string $key Identifier for the temporary uploaded file
	*@param string $dest Full path to the destination file
	*@param mixed $type Check the requested filetype with the uploaded file type for security.
	*@return bool True if the move was successful, false otherwise.
	*@todo This has to be rewritted to take care that in store there is an ARRAY of files!
	static public function UploadedFileMove( $key, $dest, $type = false )
	{ QUESTO RIVEDILO
		$store = CoreUtils::UploadedFileGet( $key );
		if ( $store !== false )
			if ( ($type === false) || ( $store["type"] == $type ) )
				return file_put_contents( $dest, $store["data"] );
		return false;
	}*/
	/**
	* Delete a temporary uploada file from the temporary folder.
	*@param string $key Identifier for the temporary uploaded file
	*@return bool True if $key is valid uploaded file
	*@todo Find a way to return false if the file is actually NOT deleted (check UploadedFileGet)
	*/
	static public function UploadedFileDelete( $key )
	{
		return CoreUtils::UploadedFileGet( $key );
	}
}

?>